#pragma once

#include <iostream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <functional>
#include <string>
#include <vector>
#include <unordered_map>
#include <pthread.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "udp_err.hpp"
#include "mutex.hpp"
#include "RingQueue.hpp"
#include "thread.hpp"

namespace ns_server
{
    
    using func_t = std::function<std::string (std::string)>;
    // const static uint16_t PORT = 8080;

    class Udp_Server
    {
        public:
            Udp_Server(const uint16_t port)
            :port_(port)
            {
                pthread_mutex_init(&lock_, nullptr);

                p = new Thread(1, std::bind(&Udp_Server::Recv, this));
                c = new Thread(2, std::bind(&Udp_Server::BroadCast, this));
            }


            void Start()
            {
                sock_ = socket(AF_INET, SOCK_DGRAM, 0);
                if(sock_ < 0)
                {
                    std::cout << "创建套接字失败！错误信息：" << strerror(errno) << std::endl;
                    exit(SOCK_ERR);
                }
                std::cout << "创建套接字成功：" << sock_ << std::endl;

                //2.给服务器指定端口号和IP地址
                struct sockaddr_in local;
                bzero(&local, 0);

                local.sin_family = AF_INET;
                local.sin_port = htons(port_);
                //1.字符串风格的IP地址，转换成四字节int
                //2.需要将主机序列转换成网络序列
                local.sin_addr.s_addr = INADDR_ANY;

                //绑定
                if(bind(sock_, (struct sockaddr*)&local, sizeof(local)) < 0)
                {
                    std::cout << "绑定失败！错误信息：" << strerror(errno) << std::endl;
                    exit(BIND_ERR);
                }
                std::cout << "绑定成功！" << std::endl;

                p->run();
                c->run();
            }
            void addUser(const std::string& name, const struct sockaddr_in& peer)
            {
                lockGuard lockguard(&lock_);
                auto iter = online_.find(name);
                if(iter != online_.end())
                {
                    return ;
                }
                online_.insert(std::pair<const std::string&, const struct sockaddr_in&>(name, peer));
            }

            void Recv()
            {
                char buff[1024];
                while(true)
                {
                    //客户端发给服务器
                    struct sockaddr_in peer;
                    socklen_t len = sizeof(peer);
                    int n = recvfrom(sock_, buff, sizeof(buff), 0, (struct sockaddr*)&peer, &len);
                    if(n > 0)
                    {
                        buff[n] = '\0';

                    }else continue;

                    //提取客户端信息
                    std::string clientIp = inet_ntoa(peer.sin_addr);
                    uint16_t clientPort = ntohs(peer.sin_port);

                    std::string name = clientIp;
                    name += "-";
                    name += to_string(clientPort);

                    addUser(name, peer);
                    rq_.push(buff);
                    // std::cout << "[" << clientIp << "-" << clientPort << "]" << "收到的消息：" << buff << std::endl;


                    // std::string response = service_(buff);
                    //服务器发给客户端
                    // sendto(sock_, response.c_str(), response.size(), 0, (struct sockaddr*)&peer, sizeof(peer)); 
                }
            }

            void BroadCast()
            {
                while(true)
                {
                    std::string sendstring;
                    rq_.pop(&sendstring);

                    std::vector<struct sockaddr_in> v;
                    {
                        lockGuard lockguard(&lock_);
                        for(auto user : online_)
                        {
                            v.push_back(user.second);
                        }
                    }

                    for(auto value : v)
                    {
                        sendto(sock_, sendstring.c_str(), sendstring.size(), 0, (struct sockaddr*)&value, sizeof(value)); 
                        // std::cout << "sendstring: " << sendstring << std::endl;
                    }
                }



            }


            ~Udp_Server()
            {
                pthread_mutex_destroy(&lock_);

                p->join();
                c->join();

                delete p;
                delete c;
            }

        private:

            int sock_;
            uint16_t port_;
            // std::string ip_;
            // func_t service_;
            std::unordered_map<std::string, struct sockaddr_in> online_;

            RingQueue<std::string> rq_;

            pthread_mutex_t lock_;

            Thread* c;
            Thread* p;

    };
}